package com.cskaoyan.wordmemorize.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cskaoyan.wordmemorize.common.constant.CommonConstant;
import com.cskaoyan.wordmemorize.common.util.DateUtil;
import com.cskaoyan.wordmemorize.converter.UserConverter;
import com.cskaoyan.wordmemorize.dao.entity.*;
import com.cskaoyan.wordmemorize.dao.mapper.*;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.dto.app.*;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.UserRemindCommand;
import com.cskaoyan.wordmemorize.service.UserCheckinService;
import com.cskaoyan.wordmemorize.service.UserRemindService;
import com.cskaoyan.wordmemorize.service.UserService;
import com.cskaoyan.wordmemorize.sms.SmsDelayMessage;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.DelayQueue;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {

    @Autowired
    UserService userService;

    @Autowired
    UserRemindService userRemindService;


    @Resource
    UserMapper userMapper;

    @Resource
    UserConverter userConverter;

    @Resource
    LevelMapper levelMapper;

    @Override
    public UserDTO getUserInfo(Long userId) {
        // 查询基本信息
        UserDO userDO = userMapper.getUserInfo(userId);

        return userConverter.userDO2DTO(userDO);
    }

    //获取下一个等级所需要天数的方法
    private Integer getNextLevelNeedDays(Integer levelValue,Integer maxSignDay) {
        Integer nextLevelNeedDays = levelValue + 1;
        //从数据库中查询此等级所需天数
       nextLevelNeedDays = userMapper.getNextLevelNeedDays(levelValue);
       return nextLevelNeedDays-maxSignDay;
    }

    @Override
    public NextLevelDTO getUserNextDTO(Long userId) {
        UserDO userDO = userMapper.getUserInfo(userId);
        //从数据库中通过等级查询用户升级需要的签到类型
        Integer signType = userMapper.getUserNextDTOSignType(userId);
        //获取升级所需天数
          //判断升级所需类型
        if (signType == 1) {
            //计算升级所需天数
              //在user_checkin_statistics中获取当前最大签到天数
            Integer maxSignDay = userMapper.getMaxContinuousDay(userId);
              //获取当前等级
            Integer levelValue = userDO.getLevelValue();
              //获取下一个等级还所需要的天数
            Integer nextLevelNeedDays = getNextLevelNeedDays(levelValue, maxSignDay);
            return new NextLevelDTO(signType, nextLevelNeedDays);
        }
        if (signType == 2) {
            //计算升级所需天数
              //在user_checkin_statistics中获取当前最大签到天数
            Integer maxSignDay = userMapper.getMaxContinuousDay(userId);
            //获取当前等级
            Integer levelValue = userDO.getLevelValue();
            //获取下一个等级还 remainedDays 天
            Integer nextLevelNeedDays = getNextLevelNeedDays(levelValue, 0);
            return new NextLevelDTO(signType, nextLevelNeedDays);
        }
        return null;
    }

    @Override
    public DisplayUserLevelDTO getUserLevelInfo(Long userId) {

        // 查询用户信息
        UserDO user = userMapper.selectById(userId);
        if (user == null) {
            return null;
        }

        // 获取当前用户的等级值
        int currentLevel = user.getLevelValue() != null ? user.getLevelValue() : 0;

        // 获取所有等级配置及关联的特权信息
        List<LevelDO> levels = levelMapper.selectAllLevelsWithPrivileges();

        // 按等级值升序排列
        levels.sort(Comparator.comparingInt(LevelDO::getLevelValue));

        // 构建等级与特权的映射关系
        Map<Long, List<LevelPrivilegeDO>> levelPrivilegeMap = new HashMap<>();
        for (LevelDO level : levels) {
            List<LevelPrivilegeDO> privileges = level.getLevelPrivileges();
            if (privileges == null) {
                privileges = new ArrayList<>();
            }
            for (LevelPrivilegeDO privilege : privileges) {
                if (privilege.getLevelId().equals(level.getId())) {
                    privileges.add(privilege);
                }
            }
            level.setLevelPrivileges(privileges);
            levelPrivilegeMap.put(level.getId(), privileges);
        }

        // 区分当前等级和未达到的等级
        List<LevelDO> nowLevelDOs = new ArrayList<>();
        List<LevelDO> upperLevelDOs = new ArrayList<>();
        for (LevelDO level : levels) {
            if (level.getLevelValue() <= currentLevel) {
                nowLevelDOs.add(level);
            } else {
                upperLevelDOs.add(level);
            }
        }

        // 将 LevelDO 转换为 LevelPageDTO
        List<LevelPageDTO> nowLevel = userConverter.levelDOsLevelPageDTOs(nowLevelDOs);
        List<LevelPageDTO> upperLevel = userConverter.levelDOsLevelPageDTOs(upperLevelDOs);

        // 封装响应数据
        DisplayUserLevelDTO displayUserLevelDTO = new DisplayUserLevelDTO();
        displayUserLevelDTO.setNowLevel(nowLevel);
        displayUserLevelDTO.setUpperLevel(upperLevel);

        return displayUserLevelDTO;
    }

    @Override
    public void updateVocCountOfDay(Long userId, Integer count) {
        userMapper.updateVocCountOfDay(userId, count);

    }

    @Override
    public void updateUserRemind(UserRemindCommand command) {
        userMapper.updateUserRemindByUserId(userConverter.userRemindCommand2DO(command));
    }

    @Override
    public UserRemindDTO getUserRemind(Long userId) {
        UserRemindDO userRemindDO = userMapper.getUserRemind(userId);
        LocalTime remindTime = userRemindDO.getRemindTime();
        String format = remindTime.format(DateTimeFormatter.ofPattern("HH:mm"));

        UserRemindDTO userRemindDTO = userConverter.userRemindDO2DTO(userRemindDO, "赶紧去背单词");

        userRemindDTO.setRemindTime(format);
        return userRemindDTO;
    }


    @Override
    public void messageRemind() {


    }

    @Override
    public PageDTO<DisplayUserVocBoundLogDTO> getUserVocBoundLog(PageRequest pageRequest, Long userId) {
        Page<DisplayUserVocBoundLogDTO> page = new Page<>(pageRequest.getPageNum(), pageRequest.getCount());
        List<DisplayUserVocBoundLogDTO> list = userMapper.userVocBoundLogPage2DisplayDTOs(page, userId);
        PageDTO<DisplayUserVocBoundLogDTO> pageDTO = userConverter.userVocBoundLogPage2PageDTO(list, page.getTotal());
        return pageDTO;
    }

    @Override
    public UserVocBoundStatisticsDTO getUserVocBoundStatistics(Long userId) {
        UserVocBoundStatisticsDO userVocBoundLogStaticsDO = userMapper.getUserVocBoundStatistics(userId);
        return userConverter.userVocBoundStatisticsDO2DisplayDTO(userVocBoundLogStaticsDO);
    }


    @Override
    public UserPageDTO getUserPage(Long userId) {
        UserDO userDO = userMapper.getUserInfo(userId);
        //获取每天规划单词学习量
        Integer vocCountOfDay = userDO.getVocCountOfDay();
        //获取总的单词上限数量
        Integer totalVocBound = userMapper.getTotalVocBoundById(userId);
        //获取购买的单词上限数量
        Integer payVocBound = userMapper.getPayVocBound(userId);
        //获取免费的单词上限数量
        Integer freeVocBound = userMapper.getFreeTotalVocBoundById(userId);
        //获取购买的补签卡数量
        Integer hasSignCard = userDO.getHasSignCard();
        UserPageDTO userPageDTO = UserPageDTO.builder()
                .vocCountOfDay(vocCountOfDay)
                .totalVocBound(totalVocBound)
                .payVocBound(payVocBound)
                .freeVocBound(freeVocBound)
                .reSignCard(hasSignCard)
                .build();
        //获取用户提醒时间
        UserRemindDTO userRemindDTO = userService.getUserRemind(userId);

        userPageDTO.setRemindTime(userRemindDTO.getRemindTime());
        return userPageDTO;
    }
}
